use anyhow::{anyhow, Error};
use arboard::Clipboard;
use base64;
use image;
use std::io::{BufWriter, Cursor, Write};

fn main() -> Result<(), Error> {
    let txt = clip2base64_datauri()?;
    write_clipboard(txt)?;
    Ok(())
}

fn png_bytes() -> Result<Vec<u8>, Error> {
    let mut ctx = Clipboard::new()?;
    let im = ctx.get_image()?;
    let channels = im.bytes.len() / (im.height * im.width);
    let raw = if channels == 4 {
        let mut buffer = Vec::with_capacity(3 * im.height * im.width);
        for chunk in im.bytes.chunks(4) {
            buffer.write(&chunk[..3])?;
        }
        buffer
    } else {
        im.bytes.to_vec()
    };
    if let Some(png) = image::RgbImage::from_raw(im.width as u32, im.height as u32, raw) {
        let mut vfile = Cursor::new(Vec::<u8>::with_capacity(3 * im.width * im.height));
        {
            let mut writer = BufWriter::new(&mut vfile);
            png.write_to(&mut writer, image::ImageOutputFormat::Png)?;
        }
        let im = vfile.get_ref().to_owned();
        Ok(im)
    } else {
        Err(anyhow!("无法将内容解析为 PNG"))
    }
}

fn clip2base64() -> Result<String, Error> {
    let im = png_bytes()?;
    let b64s = base64::encode(&im);
    Ok(b64s)
}

fn clip2base64_datauri() -> Result<String, Error> {
    let b64s = clip2base64()?;
    let data_uri = format!("data:image/png;base64,{}", &b64s);
    Ok(data_uri)
}

fn write_clipboard(content: String) -> Result<(), Error> {
    let mut ctx = Clipboard::new()?;
    ctx.set_text(content)?;
    Ok(())
}
